
#ifndef SOURCEEDIT_H
#define SOURCEEDIT_H

#include <BLine2>
#include <BSet>
#include <BTree>
#include <BImage>
#include <BSlider>
#include <BSpinBox>
#include <BComboBox>
#include <BRectArray>
#include <BPainter>
#include <BEntry>
#include <BFolder>
#include <BSource>
#include <BTextEdit>
#include <BTreeWidget>
#include <BMenu>

#include "OperaStackWidget.h"
#include "SourceFormat.h"
#include "PromptMenu.h"
#include "PromptBox.h"
#include "PromptListFilter.h"

struct SourceInfo : public BThing
{
	SourceInfo()
	{
		losted = false;
	}
	BString				fileName;
	bool				losted;
	BEntryHolder		entry;
	BStringArray		depends;
	BExpHolderArray		exps;
};
typedef BArray<SourceInfo*>	SourceInfoArray;

class SourceEdit : public BTextEdit
{
	BOBJECT(SourceEdit);
public:
	struct Chunk
	{
		Chunk()
		{
			visible = true;
			begin = -1;
			end = -1;
		}
		bool operator == (const BExp* exp) const
		{
			return this->exp == exp;
		}

		bool		visible;
		int			begin;
		int			end;
		BRect		rect;
		BRect		head;
		BRect		tail;
		BExpHolder	exp;
	};
	typedef BTree<Chunk>	ChunkTree;
public:
	SourceEdit(BWidget* parent = 0);
	~SourceEdit();

	using BTextEdit::query;
	virtual bool query(const BString& text, BValue& value) const;

protected:
	void analyseSource();

	void freshFormat(const BExpHolderArray& document);
	void drawErrorFlag(BPainter& painter, SourceFormat::Item* item);

	BString hexstr(void* ptr);
	const char* syntaxText(Syntax syntax);

	void freshExpsTree();
	BTreeItem* createTreeItem(BExp* exp);
	void freshTreeItem(BTreeItem* item);
	BString promptText(BTreeItem* item);

	void createChunk(BExp* exp, ChunkTree::iterator it);
	void createChunk(BExpHolderArray& subs, ChunkTree::iterator& it, int index);
	void freshChunk(ChunkTree::iterator& it);
	void foldedChunk(ChunkTree::iterator& it);
	ChunkTree::iterator chunkUnder(const BPoint& point);
	ChunkTree::iterator chunkUnder(ChunkTree::iterator& it, const BPoint& point);
	ChunkTree::iterator chunkOfLine(int line);
	ChunkTree::iterator chunkOfLine(ChunkTree::iterator& it, int line);
	void drawChunk(BPainter& painter, ChunkTree::iterator& it);
	void drawSpaceCode(BPainter& painter, BRect rect, BCode code);

protected:
	void slotAssetChanged(BObject* object, const BValue& value);
	void slotFreshMenu(BObject* object, const BValue& value);
	void slotTextChanged(BObject* object, const BValue& value);
	void slotSelectionChanged(BObject* object, const BValue& value);
	void slotFlushed(BObject* object, const BValue& value);
	void slotSourceMessage(BObject* object, const BValue& value);
	void slotExpsButtonToggled(BObject* object, const BValue& value);
	void slotOperaButtonToggled(BObject* object, const BValue& value);
	void slotExpTreeItemHovered(BObject* object, const BValue& value);
	void slotCleanReturnCodes();

protected:
	virtual void showEvent(const BEvent& event);
	virtual void closeEvent(const BEvent& event);

	virtual void updateEvent(const BEvent& event);
	virtual void resizeEvent(const BEvent& event);

	virtual void styleEvent(const BEvent& event);
	virtual void freshEvent(const BEvent& event);
	virtual void paintEvent(const BEvent& event);

	virtual void keyPressEvent(const BKeyEvent& keyEvent);
	virtual void keyReleaseEvent(const BKeyEvent& keyEvent);

	virtual void mousePressEvent(const BMouseEvent& mouseEvent);
	virtual void mouseReleaseEvent(const BMouseEvent& mouseEvent);
	virtual void mouseMoveEvent(const BMouseEvent& mouseEvent);
	virtual void mouseDragEvent(const BMouseEvent& mouseEvent);
	virtual void mouseClickEvent(const BMouseEvent& mouseEvent);
	virtual void mouseDoubleClickEvent(const BMouseEvent& mouseEvent);

	virtual void dragEnterEvent(const BMouseEvent& event);
	virtual void dragLeaveEvent(const BMouseEvent& event);
	virtual void dragMoveEvent(const BMouseEvent& event);
	virtual void dragDropEvent(const BMouseEvent& event);

private:
	BActionHolder			_cleanReturnAction;
	BActionHolder			_cutAction;
	BActionHolder			_copyAction;
	BActionHolder			_pasteAction;

	BComboBox*				_scriptComboBox;
	BComboBox*				_methodComboBox;
	BButton*				_expsButton;
	BButton*				_operaButton;
	BHolder<BTreeWidget>	_expsTreeWidget;
	BHolder<BWidget>		_operaStackWidget;
	BHolder<BTreeItem>		_hoveredItem;
	BSpinBox*				_lineSpinBox;
	BSpinBox*				_countSpinBox;

	BRect					_breakArea;
	BSet<int>				_breakLines;
	BRect					_chunkArea;
	BTree<Chunk>			_chunkTree;
	BMap<BString, BString>	_messagMap;
	ChunkTree::iterator		_hoveredChunk;
	bool					_selectionHovered;
	bool					_selectionPressed;
	int						_draggingIndex;
	BLine2					_draggingLine;

	SourceFormat::Item*		_hoveredFormatItem;
	double					_hoverTime;
	BHolder<PromptBox>		_promptBox;
	BHolder<PromptMenu>		_promptMenu;
	BHolder<PromptListFilter>	_promptFilter;
	BHolder<const BImage>	_minusImage;
	BHolder<const BImage>	_plusImage;
	BHolder<BCursor>		_cursorArrowRight;
};

#endif